package com.chatplus.application.common.util;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.chatplus.application.common.logging.SouthernQuietLogger;
import com.chatplus.application.common.logging.SouthernQuietLoggerFactory;

import javax.annotation.Nullable;
import java.time.Duration;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.function.Consumer;
import java.util.function.Function;

/**
 * 基于内存缓存实现的工具类
 */
public class InMemoryCaches {

    private InMemoryCaches() {
    }
    static final SouthernQuietLogger LOGGER = SouthernQuietLoggerFactory.getLogger(InMemoryCaches.class);
    /**
     * 包装方法调用，方法调用的过程中可以复用缓存，调用执行完毕清除缓存
     *
     * @param consumer consumer
     */
    public static void runWithCache(Consumer<WrapperCache> consumer) {
        WrapperCache wrapperCache = new WrapperCache(CacheBuilder.newBuilder()
            .concurrencyLevel(10)
            .expireAfterWrite(Duration.ofMinutes(1))
            .build());

        consumer.accept(wrapperCache);

        wrapperCache.invalidateAll();
        wrapperCache.cleanUp();
    }

    /**
     * 包装方法调用，方法调用的过程中可以复用缓存，调用执行完毕清除缓存
     *
     * @param function function
     * @return 方法调用的返回值
     */
    public static <R> R runWithCache(Function<WrapperCache, R> function) {
        WrapperCache wrapperCache = new WrapperCache(CacheBuilder.newBuilder()
            .concurrencyLevel(10)
            .expireAfterWrite(Duration.ofMinutes(1))
            .build());

        R result = function.apply(wrapperCache);

        wrapperCache.invalidateAll();
        wrapperCache.cleanUp();

        return result;
    }

    public static class WrapperCache {
        private final Cache<Object, Object> cache;

        public WrapperCache(Cache<Object, Object> cache) {this.cache = cache;}

        @SuppressWarnings("unchecked")
        @Nullable
        public <K, V> V get(K key, Callable<? extends V> loader) {
            try {
                return (V) cache.get(key, loader);
            } catch (ExecutionException e) {
                LOGGER.message("缓存加载数据异常").context("key", key).exception(e).warn();
                return null;
            }
        }

        @SuppressWarnings("unchecked")
        @Nullable
        public <K, V> V get(K key, Function<K, V> function) {
            try {
                return (V) cache.get(key, () -> function.apply(key));
            } catch (ExecutionException e) {
                LOGGER.message("缓存加载数据异常").context("key", key).exception(e).warn();
                return null;
            }
        }

        public void invalidateAll() {
            cache.invalidateAll();
        }

        public void cleanUp() {
            cache.cleanUp();
        }
    }
}
